package com.demo.test.utils;


import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.FileOutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 比较全面的一些方法
 *
 */
public class OfficeUtil {
    /*------------------------------------Word 插入书签---------------------------------------------------*/

    /**
     * @param p
     * @param content        内容
     * @param markId
     * @param bookMarkName   书签名
     * @param isInsert       是否插入
     * @param isNewLine      是否创建新行
     * @param fontFamily     字体
     * @param fontSize       字体大小
     * @param colorVal       颜色
     * @param isBlod
     * @param isUnderLine    是否使用下划线
     * @param underLineColor 下划线颜色
     * @param underStyle
     * @param isItalic       是否斜体
     * @param isStrike
     * @Description: 添加书签
     */
    public void addParagraphContentBookmarkBasicStyle(XWPFParagraph p,
                                                      String content, BigInteger markId, String bookMarkName,
                                                      boolean isInsert, boolean isNewLine, String fontFamily,
                                                      String fontSize, String colorVal, boolean isBlod,
                                                      boolean isUnderLine, String underLineColor,
                                                      STUnderline.Enum underStyle, boolean isItalic, boolean isStrike) {
        CTBookmark bookStart = p.getCTP().addNewBookmarkStart();
        bookStart.setId(markId);
        bookStart.setName(bookMarkName);

        XWPFRun pRun = getOrAddParagraphFirstRun(p, isInsert, isNewLine);
        setParagraphRunFontInfo(p, pRun, content, fontFamily, fontSize);
        setParagraphTextStyleInfo(p, pRun, colorVal, isBlod, isUnderLine,
                underLineColor, underStyle, isItalic, isStrike, false, false,
                false, false, false, false, false, null, false, null, false,
                null, null, null, 0, 0, 0);
        CTMarkupRange bookEnd = p.getCTP().addNewBookmarkEnd();
        bookEnd.setId(markId);
    }

    /**
     * @param p              段落
     * @param content        内容
     * @param markId
     * @param bookMarkName   书签名字
     * @param isInsert       是否插入
     * @param isNewLine      是否创建新行
     * @param fontFamily     字体
     * @param fontSize       字体大小
     * @param colorVal       字体颜色
     * @param isBlod         是否加粗
     * @param isUnderLine    是否使用下划线
     * @param underLineColor 下划线颜色
     * @param underStyle     下划线的样式
     * @param isItalic       是否使用斜体
     * @param isStrike       是否使用删除线
     * @param isDStrike      是否使用双删除线
     * @param isShadow       是否使用阴影
     * @param isVanish       是否使用弱化
     * @param isEmboss       是否使用悬浮
     * @param isImprint      是否使用水印
     * @param isOutline      是否使用大纲
     * @param isEm           是否使用着重号
     * @param emType         着重号类型
     * @param isHightLight   是否使用高亮
     * @param hightStyle     高亮的风格
     * @param isShd          是否使用底纹
     * @param shdStyle       底纹风格
     * @param shdColor       底纹颜色
     * @param verticalAlign  垂直对齐
     * @param position       位置
     * @param spacingValue   间距值
     * @param indent         缩进
     * @Description: 添加书签
     */
    public void addParagraphContentBookmark(XWPFParagraph p, String content,
                                            BigInteger markId, String bookMarkName, boolean isInsert,
                                            boolean isNewLine, String fontFamily, String fontSize,
                                            String colorVal, boolean isBlod, boolean isUnderLine,
                                            String underLineColor, STUnderline.Enum underStyle,
                                            boolean isItalic, boolean isStrike, boolean isDStrike,
                                            boolean isShadow, boolean isVanish, boolean isEmboss,
                                            boolean isImprint, boolean isOutline, boolean isEm,
                                            STEm.Enum emType, boolean isHightLight,
                                            STHighlightColor.Enum hightStyle, boolean isShd,
                                            STShd.Enum shdStyle, String shdColor, VerticalAlign verticalAlign,
                                            int position, int spacingValue, int indent) {
        CTBookmark bookStart = p.getCTP().addNewBookmarkStart();
        bookStart.setId(markId);
        bookStart.setName(bookMarkName);

        XWPFRun pRun = getOrAddParagraphFirstRun(p, isInsert, isNewLine);
        setParagraphRunFontInfo(p, pRun, content, fontFamily, fontSize);
        setParagraphTextStyleInfo(p, pRun, colorVal, isBlod, isUnderLine,
                underLineColor, underStyle, isItalic, isStrike, isDStrike,
                isShadow, isVanish, isEmboss, isImprint, isOutline, isEm,
                emType, isHightLight, hightStyle, isShd, shdStyle, shdColor,
                verticalAlign, position, spacingValue, indent);

        CTMarkupRange bookEnd = p.getCTP().addNewBookmarkEnd();
        bookEnd.setId(markId);
    }

    /*------------------------------------Word 插入超链接---------------------------------------------------*/

    /**
     * @param paragraph  段落
     * @param url        超链接
     * @param text       文本
     * @param fontFamily 字体
     * @param fontSize   字体大小
     * @param colorVal   颜色
     * @param isBlod     是否加粗
     * @param isItalic   是否使用斜体
     * @param isStrike   是否使用删除线
     * @Description: 默认的超链接样式
     */
    public void addParagraphTextHyperlinkBasicStyle(XWPFParagraph paragraph,
                                                    String url, String text, String fontFamily, String fontSize,
                                                    String colorVal, boolean isBlod, boolean isItalic, boolean isStrike) {
        addParagraphTextHyperlink(paragraph, url, text, fontFamily, fontSize,
                colorVal, isBlod, true, "0000FF", STUnderline.SINGLE, isItalic,
                isStrike, false, false, false, false, false, false, false,
                null, false, null, false, null, null, null, 0, 0, 0);
    }

    /**
     * @param paragraph      段落
     * @param url            超链接
     * @param text           文本
     * @param fontFamily     字体
     * @param fontSize       字体大小
     * @param colorVal       颜色
     * @param isBlod         是否加粗
     * @param isUnderLine    是否使用下划线
     * @param underLineColor 下划线颜色
     * @param underStyle     下划线样式
     * @param isItalic       是否使用斜体
     * @param isStrike       是否使用删除线
     * @param isDStrike      是否使用爽删除线
     * @param isShadow       是否使用阴影效果
     * @param isVanish       是否隐藏
     * @param isEmboss       是使用阳文
     * @param isImprint      是使用阴文
     * @param isOutline      是否使用大纲
     * @param isEm           是否使用着重号
     * @param emType         着重号样式
     * @param isHightLight   是否高亮(突出显示)
     * @param hightStyle     高亮的样式
     * @param isShd          是否使用底纹
     * @param shdStyle       底纹样式
     * @param shdColor       底纹颜色
     * @param verticalAlign  上标/下标
     * @param position       文本位置
     * @param spacingValue   字符间距
     * @param indent         字符间距缩进
     * @Description: 设置超链接样式
     */
    public void addParagraphTextHyperlink(XWPFParagraph paragraph, String url,
                                          String text, String fontFamily, String fontSize, String colorVal,
                                          boolean isBlod, boolean isUnderLine, String underLineColor,
                                          STUnderline.Enum underStyle, boolean isItalic, boolean isStrike,
                                          boolean isDStrike, boolean isShadow, boolean isVanish,
                                          boolean isEmboss, boolean isImprint, boolean isOutline,
                                          boolean isEm, STEm.Enum emType, boolean isHightLight,
                                          STHighlightColor.Enum hightStyle, boolean isShd,
                                          STShd.Enum shdStyle, String shdColor,
                                          STVerticalAlignRun.Enum verticalAlign, int position,
                                          int spacingValue, int indent) {
        // Add the link as External relationship
        String id = paragraph
                .getDocument()
                .getPackagePart()
                .addExternalRelationship(url,
                        XWPFRelation.HYPERLINK.getRelation()).getId();
        // Append the link and bind it to the relationship
        CTHyperlink cLink = paragraph.getCTP().addNewHyperlink();
        cLink.setId(id);

        // Create the linked text
        CTText ctText = CTText.Factory.newInstance();
        ctText.setStringValue(text);
        CTR ctr = CTR.Factory.newInstance();
        CTRPr rpr = ctr.addNewRPr();

        if (StringUtils.isNotBlank(fontFamily)) {
            // 设置字体
            CTFonts fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr
                    .addNewRFonts();
            fonts.setAscii(fontFamily);
            fonts.setEastAsia(fontFamily);
            fonts.setHAnsi(fontFamily);
        }
        if (StringUtils.isNotBlank(fontSize)) {
            // 设置字体大小
            CTHpsMeasure sz = rpr.isSetSz() ? rpr.getSz() : rpr.addNewSz();
            sz.setVal(new BigInteger(fontSize));

            CTHpsMeasure szCs = rpr.isSetSzCs() ? rpr.getSzCs() : rpr
                    .addNewSzCs();
            szCs.setVal(new BigInteger(fontSize));
        }
        // 设置超链接样式
        // 字体颜色
        if (StringUtils.isNotBlank(colorVal)) {
            CTColor color = CTColor.Factory.newInstance();
            color.setVal(colorVal);
            rpr.setColor(color);
        }
        // 加粗
        if (isBlod) {
            CTOnOff bCtOnOff = rpr.addNewB();
            bCtOnOff.setVal(STOnOff.TRUE);
        }
        // 下划线
        if (isUnderLine) {
            CTUnderline udLine = rpr.addNewU();
            udLine.setVal(underStyle);
            udLine.setColor(underLineColor);
        }
        // 倾斜
        if (isItalic) {
            CTOnOff iCtOnOff = rpr.addNewI();
            iCtOnOff.setVal(STOnOff.TRUE);
        }
        // 删除线
        if (isStrike) {
            CTOnOff sCtOnOff = rpr.addNewStrike();
            sCtOnOff.setVal(STOnOff.TRUE);
        }
        // 双删除线
        if (isDStrike) {
            CTOnOff dsCtOnOff = rpr.addNewDstrike();
            dsCtOnOff.setVal(STOnOff.TRUE);
        }
        // 阴影
        if (isShadow) {
            CTOnOff shadowCtOnOff = rpr.addNewShadow();
            shadowCtOnOff.setVal(STOnOff.TRUE);
        }
        // 隐藏
        if (isVanish) {
            CTOnOff vanishCtOnOff = rpr.addNewVanish();
            vanishCtOnOff.setVal(STOnOff.TRUE);
        }
        // 阳文
        if (isEmboss) {
            CTOnOff embossCtOnOff = rpr.addNewEmboss();
            embossCtOnOff.setVal(STOnOff.TRUE);
        }
        // 阴文
        if (isImprint) {
            CTOnOff isImprintCtOnOff = rpr.addNewImprint();
            isImprintCtOnOff.setVal(STOnOff.TRUE);
        }
        // 空心
        if (isOutline) {
            CTOnOff isOutlineCtOnOff = rpr.addNewOutline();
            isOutlineCtOnOff.setVal(STOnOff.TRUE);
        }
        // 着重号
        if (isEm) {
            CTEm em = rpr.addNewEm();
            em.setVal(emType);
        }
        // 突出显示文本
        if (isHightLight) {
            if (hightStyle != null) {
                CTHighlight hightLight = rpr.addNewHighlight();
                hightLight.setVal(hightStyle);
            }
        }
        if (isShd) {
            // 设置底纹
            CTShd shd = rpr.addNewShd();
            if (shdStyle != null) {
                shd.setVal(shdStyle);
            }
            if (shdColor != null) {
                shd.setColor(shdColor);
            }
        }
        // 上标下标
        if (verticalAlign != null) {
            rpr.addNewVertAlign().setVal(verticalAlign);
        }
        // 设置文本位置
        rpr.addNewPosition().setVal(new BigInteger(String.valueOf(position)));
        if (spacingValue != 0) {
            // 设置字符间距信息
            CTSignedTwipsMeasure ctSTwipsMeasure = rpr.addNewSpacing();
            ctSTwipsMeasure
                    .setVal(new BigInteger(String.valueOf(spacingValue)));
        }
        // 设置字符间距缩进
        if (indent > 0) {
            CTTextScale paramCTTextScale = rpr.addNewW();
            paramCTTextScale.setVal(indent);
        }
        ctr.setTArray(new CTText[]{ctText});
        cLink.setRArray(new CTR[]{ctr});
    }

    /*------------------------------------Word 页眉页脚相关---------------------------------------------------*/

    /**
     * @param document 文档
     * @Description: 页脚:显示页码信息
     */
    public void simpleNumberFooter(XWPFDocument document) throws Exception {
        CTP ctp = CTP.Factory.newInstance();
        XWPFParagraph codePara = new XWPFParagraph(ctp, document);
        XWPFRun r1 = codePara.createRun();
        r1.setText("第");
        setParagraphRunFontInfo(codePara, r1, null, "微软雅黑", "22");

        r1 = codePara.createRun();
        CTFldChar fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.BEGIN);

        r1 = codePara.createRun();
        CTText ctText = r1.getCTR().addNewInstrText();
        ctText.setStringValue("PAGE  \\* MERGEFORMAT");
        ctText.setSpace(SpaceAttribute.Space.PRESERVE);
        setParagraphRunFontInfo(codePara, r1, null, "微软雅黑", "22");

        fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.END);

        r1 = codePara.createRun();
        r1.setText("页 总共");
        setParagraphRunFontInfo(codePara, r1, null, "微软雅黑", "22");

        r1 = codePara.createRun();
        fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.BEGIN);

        r1 = codePara.createRun();
        ctText = r1.getCTR().addNewInstrText();
        ctText.setStringValue("NUMPAGES  \\* MERGEFORMAT ");
        ctText.setSpace(SpaceAttribute.Space.PRESERVE);
        setParagraphRunFontInfo(codePara, r1, null, "微软雅黑", "22");

        fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.END);

        r1 = codePara.createRun();
        r1.setText("页");
        setParagraphRunFontInfo(codePara, r1, null, "微软雅黑", "22");

        setParagraphAlignInfo(codePara, ParagraphAlignment.CENTER,
                TextAlignment.CENTER);
        codePara.setBorderTop(Borders.THICK);
        XWPFParagraph[] newparagraphs = new XWPFParagraph[1];
        newparagraphs[0] = codePara;
        CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
        XWPFHeaderFooterPolicy headerFooterPolicy = new XWPFHeaderFooterPolicy(
                document, sectPr);
        headerFooterPolicy.createFooter(STHdrFtr.DEFAULT, newparagraphs);
    }

    /**
     * @param document 文档
     * @Description: 页眉:显示时间信息
     */
    public void simpleDateHeader(XWPFDocument document) throws Exception {
        CTP ctp = CTP.Factory.newInstance();
        XWPFParagraph codePara = new XWPFParagraph(ctp, document);

        XWPFRun r1 = codePara.createRun();
        CTFldChar fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.BEGIN);

        r1 = codePara.createRun();
        CTText ctText = r1.getCTR().addNewInstrText();
        ctText.setStringValue("TIME \\@ \"EEEE\"");
        ctText.setSpace(SpaceAttribute.Space.PRESERVE);
        setParagraphRunFontInfo(codePara, r1, null, "微软雅黑", "22");

        fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.END);

        r1 = codePara.createRun();
        r1.setText("年");
        setParagraphRunFontInfo(codePara, r1, null, "微软雅黑", "22");

        r1 = codePara.createRun();
        fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.BEGIN);

        r1 = codePara.createRun();
        ctText = r1.getCTR().addNewInstrText();
        ctText.setStringValue("TIME \\@ \"O\"");
        ctText.setSpace(SpaceAttribute.Space.PRESERVE);
        setParagraphRunFontInfo(codePara, r1, null, "微软雅黑", "22");

        fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.END);

        r1 = codePara.createRun();
        r1.setText("月");
        r1.setFontSize(11);
        setParagraphRunFontInfo(codePara, r1, null, "微软雅黑", "22");

        r1 = codePara.createRun();
        fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.BEGIN);

        r1 = codePara.createRun();
        ctText = r1.getCTR().addNewInstrText();
        ctText.setStringValue("TIME \\@ \"A\"");
        ctText.setSpace(SpaceAttribute.Space.PRESERVE);
        setParagraphRunFontInfo(codePara, r1, null, "微软雅黑", "22");

        fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.END);

        r1 = codePara.createRun();
        r1.setText("日");
        r1.setFontSize(11);
        setParagraphRunFontInfo(codePara, r1, null, "微软雅黑", "22");

        setParagraphAlignInfo(codePara, ParagraphAlignment.CENTER,
                TextAlignment.CENTER);
        codePara.setBorderBottom(Borders.THICK);
        XWPFParagraph[] newparagraphs = new XWPFParagraph[1];
        newparagraphs[0] = codePara;
        CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
        XWPFHeaderFooterPolicy headerFooterPolicy = new XWPFHeaderFooterPolicy(
                document, sectPr);
        headerFooterPolicy.createHeader(STHdrFtr.DEFAULT, newparagraphs);
    }

    /*------------------------------------Word 段落相关---------------------------------------------------*/

    /**
     * @param p 段落
     * @Description: 得到段落CTPPr
     */
    public CTPPr getParagraphCTPPr(XWPFParagraph p) {
        CTPPr pPPr = null;
        if (p.getCTP() != null) {
            if (p.getCTP().getPPr() != null) {
                pPPr = p.getCTP().getPPr();
            } else {
                pPPr = p.getCTP().addNewPPr();
            }
        }
        return pPPr;
    }

    /**
     * @param p    段落
     * @param pRun
     * @Description: 得到XWPFRun的CTRPr
     */
    public CTRPr getRunCTRPr(XWPFParagraph p, XWPFRun pRun) {
        CTRPr pRpr = null;
        if (pRun.getCTR() != null) {
            pRpr = pRun.getCTR().getRPr();
            if (pRpr == null) {
                pRpr = pRun.getCTR().addNewRPr();
            }
        } else {
            pRpr = p.getCTP().addNewR().addNewRPr();
        }
        return pRpr;
    }

    /**
     * @param p         段落
     * @param isInsert  是否插入
     * @param isNewLine 是否创建新行
     * @return
     * @Description
     */
    public XWPFRun getOrAddParagraphFirstRun(XWPFParagraph p, boolean isInsert,
                                             boolean isNewLine) {
        XWPFRun pRun = null;
        if (isInsert) {
            pRun = p.createRun();
        } else {
            if (p.getRuns() != null && p.getRuns().size() > 0) {
                pRun = p.getRuns().get(0);
            } else {
                pRun = p.createRun();
            }
        }
        if (isNewLine) {
            pRun.addBreak();
        }
        return pRun;
    }

    /**
     * @param p          段落
     * @param isInsert   是否
     * @param isNewLine  是否新起一行
     * @param content    内容
     * @param fontFamily 字体
     * @param fontSize   字体大小
     * @Descritpion 设置段落文本字体信息
     */
    public void setParagraphTextFontInfo(XWPFParagraph p, boolean isInsert,
                                         boolean isNewLine, String content, String fontFamily,
                                         String fontSize) {
        XWPFRun pRun = getOrAddParagraphFirstRun(p, isInsert, isNewLine);
        setParagraphRunFontInfo(p, pRun, content, fontFamily, fontSize);
    }

    /**
     * @param p          段落
     * @param pRun
     * @param content    内容
     * @param fontFamily 字体
     * @param fontSize   字体大小
     * @Description 设置字体信息
     */
    public void setParagraphRunFontInfo(XWPFParagraph p, XWPFRun pRun,
                                        String content, String fontFamily, String fontSize) {
        CTRPr pRpr = getRunCTRPr(p, pRun);
        if (StringUtils.isNotBlank(content)) {
            pRun.setText(content);
        }
        // 设置字体
        CTFonts fonts = pRpr.isSetRFonts() ? pRpr.getRFonts() : pRpr
                .addNewRFonts();
        fonts.setAscii(fontFamily);
        fonts.setEastAsia(fontFamily);
        fonts.setHAnsi(fontFamily);

        // 设置字体大小
        CTHpsMeasure sz = pRpr.isSetSz() ? pRpr.getSz() : pRpr.addNewSz();
        sz.setVal(new BigInteger(fontSize));

        CTHpsMeasure szCs = pRpr.isSetSzCs() ? pRpr.getSzCs() : pRpr
                .addNewSzCs();
        szCs.setVal(new BigInteger(fontSize));
    }

    /**
     * @param p              段落
     * @param pRun
     * @param colorVal       色彩值
     * @param isBlod         是否加粗
     * @param isUnderLine    是否使用下划线
     * @param underLineColor 下划线颜色
     * @param underStyle     下划线样式
     * @param isItalic       是否倾斜
     * @param isStrike       是否使用删除线
     * @param isHightLight   是否高亮(突出显示)
     * @param hightStyle     高亮的样式
     * @param isShd          是否使用底纹
     * @param shdStyle       底纹样式
     * @param shdColor       底纹颜色
     * @Description 设置段落基本样式
     */
    public void setParagraphTextBasicStyleInfo(XWPFParagraph p, XWPFRun pRun,
                                               String colorVal, boolean isBlod, boolean isUnderLine,
                                               String underLineColor, STUnderline.Enum underStyle,
                                               boolean isItalic, boolean isStrike, boolean isHightLight,
                                               STHighlightColor.Enum hightStyle, boolean isShd,
                                               STShd.Enum shdStyle, String shdColor) {
        setParagraphTextStyleInfo(p, pRun, colorVal, isBlod, isUnderLine,
                underLineColor, underStyle, isItalic, isStrike, false, false,
                false, false, false, false, false, null, isHightLight,
                hightStyle, isShd, shdStyle, shdColor, null, 0, 0, 0);
    }

    /**
     * @param verticalAlign SUPERSCRIPT上标 SUBSCRIPT下标
     * @param position      字符间距位置：>0提升 <0降低=磅值*2 如3磅=6
     * @param spacingValue  字符间距间距 >0加宽 <0紧缩 =磅值*20 如2磅=40
     * @param indent        字符间距缩进 <100 缩
     * @Description: 设置段落文本样式(高亮与底纹显示效果不同)设置字符间距信息(CTSignedTwipsMeasure)
     */
    public void setParagraphTextSimpleStyleInfo(XWPFParagraph p, XWPFRun pRun,
                                                String colorVal, boolean isBlod, boolean isUnderLine,
                                                String underLineColor, STUnderline.Enum underStyle,
                                                boolean isItalic, boolean isStrike, boolean isHightLight,
                                                STHighlightColor.Enum hightStyle, boolean isShd,
                                                STShd.Enum shdStyle, String shdColor, VerticalAlign verticalAlign,
                                                int position, int spacingValue, int indent) {
        setParagraphTextStyleInfo(p, pRun, colorVal, isBlod, isUnderLine,
                underLineColor, underStyle, isItalic, isStrike, false, false,
                false, false, false, false, false, null, isHightLight,
                hightStyle, isShd, shdStyle, shdColor, verticalAlign, position,
                spacingValue, indent);
    }

    /**
     * @param verticalAlign SUPERSCRIPT上标 SUBSCRIPT下标
     * @param position      字符间距位置：>0提升 <0降低=磅值*2 如3磅=6
     * @param spacingValue  字符间距间距 >0加宽 <0紧缩 =磅值*20 如2磅=40
     * @param indent        字符间距缩进 <100 缩
     * @Description: 设置段落文本样式(高亮与底纹显示效果不同)设置字符间距信息(CTSignedTwipsMeasure)
     */
    public void setParagraphTextStyleInfo(XWPFParagraph p, XWPFRun pRun,
                                          String colorVal, boolean isBlod, boolean isUnderLine,
                                          String underLineColor, STUnderline.Enum underStyle,
                                          boolean isItalic, boolean isStrike, boolean isDStrike,
                                          boolean isShadow, boolean isVanish, boolean isEmboss,
                                          boolean isImprint, boolean isOutline, boolean isEm,
                                          STEm.Enum emType, boolean isHightLight,
                                          STHighlightColor.Enum hightStyle, boolean isShd,
                                          STShd.Enum shdStyle, String shdColor, VerticalAlign verticalAlign,
                                          int position, int spacingValue, int indent) {
        if (pRun == null) {
            return;
        }
        CTRPr pRpr = getRunCTRPr(p, pRun);
        if (colorVal != null) {
            pRun.setColor(colorVal);
        }
        // 设置字体样式
        // 加粗
        if (isBlod) {
            pRun.setBold(isBlod);
        }
        // 倾斜
        if (isItalic) {
            pRun.setItalic(isItalic);
        }
        // 删除线
        if (isStrike) {
            pRun.setStrike(isStrike);
        }
        // 双删除线
        if (isDStrike) {
            CTOnOff dsCtOnOff = pRpr.isSetDstrike() ? pRpr.getDstrike() : pRpr
                    .addNewDstrike();
            dsCtOnOff.setVal(STOnOff.TRUE);
        }
        // 阴影
        if (isShadow) {
            CTOnOff shadowCtOnOff = pRpr.isSetShadow() ? pRpr.getShadow()
                    : pRpr.addNewShadow();
            shadowCtOnOff.setVal(STOnOff.TRUE);
        }
        // 隐藏
        if (isVanish) {
            CTOnOff vanishCtOnOff = pRpr.isSetVanish() ? pRpr.getVanish()
                    : pRpr.addNewVanish();
            vanishCtOnOff.setVal(STOnOff.TRUE);
        }
        // 阳文
        if (isEmboss) {
            CTOnOff embossCtOnOff = pRpr.isSetEmboss() ? pRpr.getEmboss()
                    : pRpr.addNewEmboss();
            embossCtOnOff.setVal(STOnOff.TRUE);
        }
        // 阴文
        if (isImprint) {
            CTOnOff isImprintCtOnOff = pRpr.isSetImprint() ? pRpr.getImprint()
                    : pRpr.addNewImprint();
            isImprintCtOnOff.setVal(STOnOff.TRUE);
        }
        // 空心
        if (isOutline) {
            CTOnOff isOutlineCtOnOff = pRpr.isSetOutline() ? pRpr.getOutline()
                    : pRpr.addNewOutline();
            isOutlineCtOnOff.setVal(STOnOff.TRUE);
        }
        // 着重号
        if (isEm) {
            CTEm em = pRpr.isSetEm() ? pRpr.getEm() : pRpr.addNewEm();
            em.setVal(emType);
        }
        // 设置下划线样式
        if (isUnderLine) {
            CTUnderline u = pRpr.isSetU() ? pRpr.getU() : pRpr.addNewU();
            if (underStyle != null) {
                u.setVal(underStyle);
            }
            if (underLineColor != null) {
                u.setColor(underLineColor);
            }
        }
        // 设置突出显示文本
        if (isHightLight) {
            if (hightStyle != null) {
                CTHighlight hightLight = pRpr.isSetHighlight() ? pRpr
                        .getHighlight() : pRpr.addNewHighlight();
                hightLight.setVal(hightStyle);
            }
        }
        if (isShd) {
            // 设置底纹
            CTShd shd = pRpr.isSetShd() ? pRpr.getShd() : pRpr.addNewShd();
            if (shdStyle != null) {
                shd.setVal(shdStyle);
            }
            if (shdColor != null) {
                shd.setColor(shdColor);
            }
        }
        // 上标下标
        if (verticalAlign != null) {
            pRun.setSubscript(verticalAlign);
        }
        // 设置文本位置
        pRun.setTextPosition(position);
        if (spacingValue > 0) {
            // 设置字符间距信息
            CTSignedTwipsMeasure ctSTwipsMeasure = pRpr.isSetSpacing() ? pRpr
                    .getSpacing() : pRpr.addNewSpacing();
            ctSTwipsMeasure
                    .setVal(new BigInteger(String.valueOf(spacingValue)));
        }
        if (indent > 0) {
            CTTextScale paramCTTextScale = pRpr.isSetW() ? pRpr.getW() : pRpr
                    .addNewW();
            paramCTTextScale.setVal(indent);
        }
    }

    /**
     * @param p        段落
     * @param isShd    是否使用底纹
     * @param shdStyle 底纹样式
     * @param shdColor 底纹颜色
     * @Description: 设置段落底纹(对整段文字起作用)
     */
    public void setParagraphShdStyle(XWPFParagraph p, boolean isShd,
                                     STShd.Enum shdStyle, String shdColor) {
        CTPPr pPpr = getParagraphCTPPr(p);
        CTShd shd = pPpr.isSetShd() ? pPpr.getShd() : pPpr.addNewShd();
        if (shdStyle != null) {
            shd.setVal(shdStyle);
        }
        if (shdColor != null) {
            shd.setColor(shdColor);
        }
    }

    /**
     * @param p           段落
     * @param isSpace     是否设置段前/段后间隔
     * @param before      段前磅数
     * @param after       段后磅数
     * @param beforeLines 段前行数
     * @param afterLines  段后行数
     * @param isLine      是否设置行间距
     * @param line        行间距
     * @param lineValue   行间距(行数)
     * @Description: 设置段落间距信息, 一行=100 一磅=20
     */
    public void setParagraphSpacingInfo(XWPFParagraph p, boolean isSpace,
                                        String before, String after, String beforeLines, String afterLines,
                                        boolean isLine, String line, STLineSpacingRule.Enum lineValue) {
        CTPPr pPPr = getParagraphCTPPr(p);
        CTSpacing pSpacing = pPPr.getSpacing() != null ? pPPr.getSpacing()
                : pPPr.addNewSpacing();
        if (isSpace) {
            // 段前磅数
            if (before != null) {
                pSpacing.setBefore(new BigInteger(before));
            }
            // 段后磅数
            if (after != null) {
                pSpacing.setAfter(new BigInteger(after));
            }
            // 段前行数
            if (beforeLines != null) {
                pSpacing.setBeforeLines(new BigInteger(beforeLines));
            }
            // 段后行数
            if (afterLines != null) {
                pSpacing.setAfterLines(new BigInteger(afterLines));
            }
        }
        // 间距
        if (isLine) {
            if (line != null) {
                pSpacing.setLine(new BigInteger(line));
            }
            if (lineValue != null) {
                pSpacing.setLineRule(lineValue);
            }
        }
    }

    /**
     * @param p             段落
     * @param firstLine
     * @param firstLineChar
     * @param hanging
     * @param hangingChar
     * @param right
     * @param rigthChar
     * @param left
     * @param leftChar
     * @Description 设置段落缩进信息 1厘米≈567
     */
    public void setParagraphIndInfo(XWPFParagraph p, String firstLine,
                                    String firstLineChar, String hanging, String hangingChar,
                                    String right, String rigthChar, String left, String leftChar) {
        CTPPr pPPr = getParagraphCTPPr(p);
        CTInd pInd = pPPr.getInd() != null ? pPPr.getInd() : pPPr.addNewInd();
        if (firstLine != null) {
            pInd.setFirstLine(new BigInteger(firstLine));
        }
        if (firstLineChar != null) {
            pInd.setFirstLineChars(new BigInteger(firstLineChar));
        }
        if (hanging != null) {
            pInd.setHanging(new BigInteger(hanging));
        }
        if (hangingChar != null) {
            pInd.setHangingChars(new BigInteger(hangingChar));
        }
        if (left != null) {
            pInd.setLeft(new BigInteger(left));
        }
        if (leftChar != null) {
            pInd.setLeftChars(new BigInteger(leftChar));
        }
        if (right != null) {
            pInd.setRight(new BigInteger(right));
        }
        if (rigthChar != null) {
            pInd.setRightChars(new BigInteger(rigthChar));
        }
    }

    /**
     * @param p         段落
     * @param lborder   左-边框
     * @param tBorders  顶-边框
     * @param rBorders  右-边框
     * @param bBorders  底-边框
     * @param btborders 上下边框
     * @Description 设置段落边框
     */
    public void setParagraphBorders(XWPFParagraph p, Borders lborder,
                                    Borders tBorders, Borders rBorders, Borders bBorders,
                                    Borders btborders) {
        if (lborder != null) {
            p.setBorderLeft(lborder);
        }
        if (tBorders != null) {
            p.setBorderTop(tBorders);
        }
        if (rBorders != null) {
            p.setBorderRight(rBorders);
        }
        if (bBorders != null) {
            p.setBorderBottom(bBorders);
        }
        if (btborders != null) {
            p.setBorderBetween(btborders);
        }
    }

    /**
     * @param p
     * @param pAlign
     * @param valign
     * @Description: 设置段落对齐
     */
    public void setParagraphAlignInfo(XWPFParagraph p,
                                      ParagraphAlignment pAlign, TextAlignment valign) {
        if (pAlign != null) {
            p.setAlignment(pAlign);
        }
        if (valign != null) {
            p.setVerticalAlignment(valign);
        }
    }

    /*------------------------------------Word 表格相关---------------------------------------------------*/

    /**
     * @param xdoc 文档
     * @param pos  位置
     * @Description:删除指定位置的表格,被删除表格后的索引位置
     */
    public void deleteTableByIndex(XWPFDocument xdoc, int pos) {
        Iterator<IBodyElement> bodyElement = xdoc.getBodyElementsIterator();
        int eIndex = 0, tableIndex = -1;
        while (bodyElement.hasNext()) {
            IBodyElement element = bodyElement.next();
            BodyElementType elementType = element.getElementType();
            if (elementType == BodyElementType.TABLE) {
                tableIndex++;
                if (tableIndex == pos) {
                    break;
                }
            }
            eIndex++;
        }
        xdoc.removeBodyElement(eIndex);
    }

    /**
     * @param xdoc  文档
     * @param index 索引
     * @return
     * @Description: 通过索引得到表格
     */
    public XWPFTable getTableByIndex(XWPFDocument xdoc, int index) {
        List<XWPFTable> tablesList = getAllTable(xdoc);
        if (tablesList == null || index < 0 || index > tablesList.size()) {
            return null;
        }
        return tablesList.get(index);
    }

    public List<XWPFTable> getAllTable(XWPFDocument xdoc) {
        return xdoc.getTables();
    }

    /**
     * @param table 表格
     * @Description: 得到表格内容(第一次跨行单元格视为一个 ， 第二次跳过跨行合并的单元格)
     */
    public List<List<String>> getTableRContent(XWPFTable table) {
        List<List<String>> tableContentList = new ArrayList<List<String>>();
        for (int rowIndex = 0, rowLen = table.getNumberOfRows(); rowIndex < rowLen; rowIndex++) {
            XWPFTableRow row = table.getRow(rowIndex);
            List<String> cellContentList = new ArrayList<String>();
            for (int colIndex = 0, colLen = row.getTableCells().size(); colIndex < colLen; colIndex++) {
                XWPFTableCell cell = row.getCell(colIndex);
                CTTc ctTc = cell.getCTTc();
                if (ctTc.isSetTcPr()) {
                    CTTcPr tcPr = ctTc.getTcPr();
                    if (tcPr.isSetHMerge()) {
                        CTHMerge hMerge = tcPr.getHMerge();
                        if (STMerge.RESTART.equals(hMerge.getVal())) {
                            cellContentList.add(getTableCellContent(cell));
                        }
                    } else if (tcPr.isSetVMerge()) {
                        CTVMerge vMerge = tcPr.getVMerge();
                        if (STMerge.RESTART.equals(vMerge.getVal())) {
                            cellContentList.add(getTableCellContent(cell));
                        }
                    } else {
                        cellContentList.add(getTableCellContent(cell));
                    }
                }
            }
            tableContentList.add(cellContentList);
        }
        return tableContentList;
    }

    /**
     * @param table 操作的目标表格
     * @Description: 得到表格内容, 合并后的单元格视为一个单元格
     */
    public List<List<String>> getTableContent(XWPFTable table) {
        List<List<String>> tableContentList = new ArrayList<List<String>>();
        for (int rowIndex = 0, rowLen = table.getNumberOfRows(); rowIndex < rowLen; rowIndex++) {
            XWPFTableRow row = table.getRow(rowIndex);
            List<String> cellContentList = new ArrayList<String>();
            for (int colIndex = 0, colLen = row.getTableCells().size(); colIndex < colLen; colIndex++) {
                XWPFTableCell cell = row.getCell(colIndex);
                cellContentList.add(getTableCellContent(cell));
            }
            tableContentList.add(cellContentList);
        }
        return tableContentList;
    }

    /**
     * @param cell 表格单元
     * @return
     * @Description: 得到表格单元中的内容
     */
    public String getTableCellContent(XWPFTableCell cell) {
        StringBuffer sb = new StringBuffer();
        List<XWPFParagraph> cellPList = cell.getParagraphs();
        if (cellPList != null && cellPList.size() > 0) {
            for (XWPFParagraph xwpfPr : cellPList) {
                List<XWPFRun> runs = xwpfPr.getRuns();
                if (runs != null && runs.size() > 0) {
                    for (XWPFRun xwpfRun : runs) {
                        sb.append(xwpfRun.getText(0));
                    }
                }
            }
        }
        return sb.toString();
    }

    /**
     * @Description: 创建表格, 创建后表格至少有1行1列, 设置列宽
     */
    public XWPFTable createTable(XWPFDocument xdoc, int rowSize, int cellSize,
                                 boolean isSetColWidth, int[] colWidths) {
        XWPFTable table = xdoc.createTable(rowSize, cellSize);
        if (isSetColWidth) {
            CTTbl ttbl = table.getCTTbl();
            CTTblGrid tblGrid = ttbl.addNewTblGrid();
            for (int j = 0, len = Math.min(cellSize, colWidths.length); j < len; j++) {
                CTTblGridCol gridCol = tblGrid.addNewGridCol();
                gridCol.setW(new BigInteger(String.valueOf(colWidths[j])));
            }
        }
        return table;
    }

    /**
     * @Description: 设置表格总宽度与水平对齐方式
     */
    public void setTableWidthAndHAlign(XWPFTable table, String width,
                                       STJc.Enum enumValue) {
        CTTblPr tblPr = getTableCTTblPr(table);
        CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr
                .addNewTblW();
        if (enumValue != null) {
            CTJc cTJc = tblPr.addNewJc();
            cTJc.setVal(enumValue);
        }
        tblWidth.setW(new BigInteger(width));
        tblWidth.setType(STTblWidth.DXA);
    }

    /**
     * @Description: 得到Table的CTTblPr, 不存在则新建
     */
    public CTTblPr getTableCTTblPr(XWPFTable table) {
        CTTbl ttbl = table.getCTTbl();
        CTTblPr tblPr = ttbl.getTblPr() == null ? ttbl.addNewTblPr() : ttbl
                .getTblPr();
        return tblPr;
    }

    /**
     * @Description: 得到Table的边框, 不存在则新建
     */
    public CTTblBorders getTableBorders(XWPFTable table) {
        CTTblPr tblPr = getTableCTTblPr(table);
        CTTblBorders tblBorders = tblPr.isSetTblBorders() ? tblPr
                .getTblBorders() : tblPr.addNewTblBorders();
        return tblBorders;
    }

    /**
     * @Description: 设置表格边框样式
     */
    public void setTableBorders(XWPFTable table, CTBorder left, CTBorder top,
                                CTBorder right, CTBorder bottom) {
        CTTblBorders tblBorders = getTableBorders(table);
        if (left != null) {
            tblBorders.setLeft(left);
        }
        if (top != null) {
            tblBorders.setTop(top);
        }
        if (right != null) {
            tblBorders.setRight(right);
        }
        if (bottom != null) {
            tblBorders.setBottom(bottom);
        }
    }

    /**
     * @Description: 设置Table的边框
     */
    public void setTableBorders(XWPFTable table, STBorder.Enum borderType, String size, String color, String space) {
        CTTblPr tblPr = getTableCTTblPr(table);
        CTTblBorders borders = tblPr.isSetTblBorders() ? tblPr.getTblBorders() : tblPr.addNewTblBorders();
        CTBorder hBorder = borders.isSetInsideH() ? borders.getInsideH() : borders.addNewInsideH();
        hBorder.setVal(borderType);
        hBorder.setSz(new BigInteger(size));
        hBorder.setColor(color);
        hBorder.setSpace(new BigInteger(space));

        CTBorder vBorder = borders.isSetInsideV() ? borders.getInsideV() : borders.addNewInsideV();
        vBorder.setVal(borderType);
        vBorder.setSz(new BigInteger(size));
        vBorder.setColor(color);
        vBorder.setSpace(new BigInteger(space));

        CTBorder lBorder = borders.isSetLeft() ? borders.getLeft() : borders.addNewLeft();
        lBorder.setVal(borderType);
        lBorder.setSz(new BigInteger(size));
        lBorder.setColor(color);
        lBorder.setSpace(new BigInteger(space));

        CTBorder rBorder = borders.isSetRight() ? borders.getRight() : borders
                .addNewRight();
        rBorder.setVal(borderType);
        rBorder.setSz(new BigInteger(size));
        rBorder.setColor(color);
        rBorder.setSpace(new BigInteger(space));

        CTBorder tBorder = borders.isSetTop() ? borders.getTop() : borders
                .addNewTop();
        tBorder.setVal(borderType);
        tBorder.setSz(new BigInteger(size));
        tBorder.setColor(color);
        tBorder.setSpace(new BigInteger(space));

        CTBorder bBorder = borders.isSetBottom() ? borders.getBottom()
                : borders.addNewBottom();
        bBorder.setVal(borderType);
        bBorder.setSz(new BigInteger(size));
        bBorder.setColor(color);
        bBorder.setSpace(new BigInteger(space));
    }

    /**
     * @param table 操作的目标表格
     * @param index 为新增行的目标行位置(不能大于表行数)
     * @Description: 表格指定位置插入一行
     */
    public void insertTableRowAtIndex(XWPFTable table, int index) {
        XWPFTableRow firstRow = table.getRow(0);
        XWPFTableRow row = table.insertNewTableRow(index);
        if (row == null) {
            return;
        }
        CTTbl ctTbl = table.getCTTbl();
        CTTblGrid tblGrid = ctTbl.getTblGrid();
        int cellSize = 0;
        boolean isAdd = false;
        if (tblGrid != null) {
            List<CTTblGridCol> gridColList = tblGrid.getGridColList();
            if (gridColList != null && gridColList.size() > 0) {
                isAdd = true;
                for (CTTblGridCol ctlCol : gridColList) {
                    XWPFTableCell cell = row.addNewTableCell();
                    setCellWidthAndVAlign(cell, ctlCol.getW().toString(),
                            STTblWidth.DXA, null);
                }
            }
        }
        // 大部分都不会走到这一步
        if (!isAdd) {
            cellSize = getCellSizeWithMergeNum(firstRow);
            for (int i = 0; i < cellSize; i++) {
                row.addNewTableCell();
            }
        }
    }

    /**
     * @param table 操作的目标表格
     * @param index 操作的目标表格的行
     * @Description: 删除表一行
     */
    public void deleteTableRow(XWPFTable table, int index) {
        table.removeRow(index);
    }

    /**
     * @Description: 统计列数(包括合并的列数)
     */
    public int getCellSizeWithMergeNum(XWPFTableRow row) {
        List<XWPFTableCell> firstRowCellList = row.getTableCells();
        int cellSize = firstRowCellList.size();
        for (XWPFTableCell xwpfTableCell : firstRowCellList) {
            CTTc ctTc = xwpfTableCell.getCTTc();
            if (ctTc.isSetTcPr()) {
                CTTcPr tcPr = ctTc.getTcPr();
                if (tcPr.isSetGridSpan()) {
                    CTDecimalNumber gridSpan = tcPr.getGridSpan();
                    cellSize += gridSpan.getVal().intValue() - 1;
                }
            }
        }
        return cellSize;
    }

    /**
     * @Description: 得到CTTrPr, 不存在则新建
     */
    public CTTrPr getRowCTTrPr(XWPFTableRow row) {
        CTRow ctRow = row.getCtRow();
        CTTrPr trPr = ctRow.isSetTrPr() ? ctRow.getTrPr() : ctRow.addNewTrPr();
        return trPr;
    }

    /**
     * @Description: 设置行高
     */
    public void setRowHeight(XWPFTableRow row, String hight,
                             STHeightRule.Enum heigthEnum) {
        CTTrPr trPr = getRowCTTrPr(row);
        CTHeight trHeight;
        if (trPr.getTrHeightList() != null && trPr.getTrHeightList().size() > 0) {
            trHeight = trPr.getTrHeightList().get(0);
        } else {
            trHeight = trPr.addNewTrHeight();
        }
        trHeight.setVal(new BigInteger(hight));
        if (heigthEnum != null) {
            trHeight.setHRule(heigthEnum);
        }
    }

    /**
     * @Description: 隐藏行
     */
    public void setRowHidden(XWPFTableRow row, boolean hidden) {
        CTTrPr trPr = getRowCTTrPr(row);
        CTOnOff hiddenValue;
        if (trPr.getHiddenList() != null && trPr.getHiddenList().size() > 0) {
            hiddenValue = trPr.getHiddenList().get(0);
        } else {
            hiddenValue = trPr.addNewHidden();
        }
        if (hidden) {
            hiddenValue.setVal(STOnOff.TRUE);
        } else {
            hiddenValue.setVal(STOnOff.FALSE);
        }
        setRowAllCellHidden(row, hidden);
    }

    /**
     * @param row      列
     * @param isVanish 是否隐藏
     * @Description: 设置表格中某一列整列隐藏
     */
    public void setRowAllCellHidden(XWPFTableRow row, boolean isVanish) {
        for (int colIndex = 0, colLen = row.getTableCells().size(); colIndex < colLen; colIndex++) {
            XWPFTableCell cell = row.getCell(colIndex);
            setCellHidden(cell, isVanish);
        }
    }

    /**
     * @param table    目标表格
     * @param rowIndex 列索引
     * @param col      目标单元格
     * @param content  内容
     * @Description: 设置单元格内容
     */
    public void setCellNewContent(XWPFTable table, int rowIndex, int col,
                                  String content) {
        XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
        XWPFParagraph p = getCellFirstParagraph(cell);
        List<XWPFRun> cellRunList = p.getRuns();
        if (cellRunList == null || cellRunList.size() == 0) {
            return;
        }
        for (int i = cellRunList.size() - 1; i >= 1; i--) {
            p.removeRun(i);
        }
        XWPFRun run = cellRunList.get(0);
        run.setText(content);
    }

    /**
     * @param table    目标表格
     * @param rowIndex 列索引
     * @param col      目标单元格
     * @Description: 删除单元格内容
     */
    public void deleteCellContent(XWPFTable table, int rowIndex, int col) {
        XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
        XWPFParagraph p = getCellFirstParagraph(cell);
        List<XWPFRun> cellRunList = p.getRuns();
        if (cellRunList == null || cellRunList.size() == 0) {
            return;
        }
        for (int i = cellRunList.size() - 1; i >= 0; i--) {
            p.removeRun(i);
        }
    }

    /**
     * @param table    目标表格
     * @param rowIndex 列索引
     * @param col      目标单元格
     * @Description: 隐藏单元格内容
     */
    public void setHiddenCellContent(XWPFTable table, int rowIndex, int col) {
        XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
        setCellHidden(cell, true);
    }

    /**
     * @param cell     目标单元格
     * @param isVanish 是否隐藏
     * @Description: 隐藏单元格
     */
    public void setCellHidden(XWPFTableCell cell, boolean isVanish) {
        XWPFParagraph p = getCellFirstParagraph(cell);
        CTPPr pPPr = getParagraphCTPPr(p);
        CTParaRPr paRpr = pPPr.isSetRPr() ? pPPr.getRPr() : pPPr.addNewRPr();
        CTOnOff vanishCtOnOff = paRpr.isSetVanish() ? paRpr.getVanish() : paRpr
                .addNewVanish();
        if (isVanish) {
            vanishCtOnOff.setVal(STOnOff.TRUE);
        } else {
            vanishCtOnOff.setVal(STOnOff.FALSE);
        }
        List<XWPFRun> cellRunList = p.getRuns();
        if (cellRunList == null || cellRunList.size() == 0) {
            return;
        }
        for (XWPFRun xwpfRun : cellRunList) {
            CTRPr pRpr = getRunCTRPr(p, xwpfRun);
            vanishCtOnOff = pRpr.isSetVanish() ? pRpr.getVanish() : pRpr
                    .addNewVanish();
            if (isVanish) {
                vanishCtOnOff.setVal(STOnOff.TRUE);
            } else {
                vanishCtOnOff.setVal(STOnOff.FALSE);
            }
        }
    }

    /**
     * @Description: 得到Cell的CTTcPr, 不存在则新建
     */
    public CTTcPr getCellCTTcPr(XWPFTableCell cell) {
        CTTc cttc = cell.getCTTc();
        CTTcPr tcPr = cttc.isSetTcPr() ? cttc.getTcPr() : cttc.addNewTcPr();
        return tcPr;
    }

    /**
     * @Description: 设置垂直对齐方式
     */
    public void setCellVAlign(XWPFTableCell cell, STVerticalJc.Enum vAlign) {
        setCellWidthAndVAlign(cell, null, null, vAlign);
    }

    /**
     * @Description: 设置列宽和垂直对齐方式
     */
    public void setCellWidthAndVAlign(XWPFTableCell cell, String width,
                                      STTblWidth.Enum typeEnum, STVerticalJc.Enum vAlign) {
        CTTcPr tcPr = getCellCTTcPr(cell);
        CTTblWidth tcw = tcPr.isSetTcW() ? tcPr.getTcW() : tcPr.addNewTcW();
        if (width != null) {
            tcw.setW(new BigInteger(width));
        }
        if (typeEnum != null) {
            tcw.setType(typeEnum);
        }
        if (vAlign != null) {
            CTVerticalJc vJc = tcPr.isSetVAlign() ? tcPr.getVAlign() : tcPr
                    .addNewVAlign();
            vJc.setVal(vAlign);
        }
    }

    /**
     * @Description: 设置底纹
     */
    public void setCellShdStyle(XWPFTableCell cell, boolean isShd, String shdColor, STShd.Enum shdStyle) {
        CTTcPr tcPr = getCellCTTcPr(cell);
        if (isShd) {
            // 设置底纹
            CTShd shd = tcPr.isSetShd() ? tcPr.getShd() : tcPr.addNewShd();
            if (shdStyle != null) {
                shd.setVal(shdStyle);
            }
            if (shdColor != null) {
                shd.setColor(shdColor);
                shd.setFill(shdColor);
            }
        }
    }

    /**
     * @Description: 设置单元格Margin
     */
    public void setTableCellMargin(XWPFTable table, int top, int left, int bottom, int right) {
        table.setCellMargins(top, left, bottom, right);
    }

    /**
     * @Description: 得到单元格第一个Paragraph
     */
    public XWPFParagraph getCellFirstParagraph(XWPFTableCell cell) {
        XWPFParagraph p;
        if (cell.getParagraphs() != null && cell.getParagraphs().size() > 0) {
            p = cell.getParagraphs().get(0);
        } else {
            p = cell.addParagraph();
        }
        return p;
    }

    /**
     * @Description: 跨列合并
     */
    public void mergeCellsHorizontal(XWPFTable table, int row, int fromCell,
                                     int toCell) {
        for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {
            XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
            if (cellIndex == fromCell) {
                // The first merged cell is set with RESTART merge value
                getCellCTTcPr(cell).addNewHMerge().setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one,are set with CONTINUE
                getCellCTTcPr(cell).addNewHMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

    /**
     * @Description: 跨行合并
     * @see http://stackoverflow.com/questions/24907541/row-span-with-xwpftable
     */
    public void mergeCellsVertically(XWPFTable table, int col, int fromRow,
                                     int toRow) {
        for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
            XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
            if (rowIndex == fromRow) {
                // The first merged cell is set with RESTART merge value
                getCellCTTcPr(cell).addNewVMerge().setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one,are set with CONTINUE
                getCellCTTcPr(cell).addNewVMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

    /*------------------------------------Word 文档信息---------------------------------------------------*/

    /**
     * @param document 文档
     * @param bgColor  背景色
     * @Description: 设置页面背景色
     */
    public void setDocumentbackground(XWPFDocument document, String bgColor) {
        CTBackground bg = document.getDocument().isSetBackground() ? document
                .getDocument().getBackground() : document.getDocument()
                .addNewBackground();
        bg.setColor(bgColor);
    }

    /**
     * @param document 文档
     * @return
     * @Description: 获得文档的 CTSectPr
     */
    public CTSectPr getDocumentCTSectPr(XWPFDocument document) {
        CTSectPr sectPr = document.getDocument().getBody().isSetSectPr() ? document
                .getDocument().getBody().getSectPr()
                : document.getDocument().getBody().addNewSectPr();
        return sectPr;
    }

    /**
     * @Description: 页面Break
     */
    public void addNewPageBreak(XWPFDocument document, BreakType breakType) {
        XWPFParagraph xp = document.createParagraph();
        xp.createRun().addBreak(breakType);
    }

    /**
     * @param document 文档
     * @param top      顶
     * @param right    右
     * @param bottom   底
     * @param left     左
     * @Description: 设置页面边框
     */
    public void setPgBorders(XWPFDocument document, CTBorder top,
                             CTBorder right, CTBorder bottom, CTBorder left) {
        CTSectPr sectPr = getDocumentCTSectPr(document);
        CTPageBorders pd = sectPr.isSetPgBorders() ? sectPr.getPgBorders()
                : sectPr.addNewPgBorders();
        /*
         * CTBorder bb = pd.addNewBottom(); bb.setVal(STBorder.SINGLE);
         * bb.setSz(new BigInteger("4")); bb.setSpace(new BigInteger("24"));
         * bb.setColor("FBB61F");
         */
        if (top != null) {
            pd.setTop(top);
        }
        if (right != null) {
            pd.setRight(right);
        }
        if (bottom != null) {
            pd.setBottom(bottom);
        }
        if (left != null) {
            pd.setLeft(left);
        }
    }

    /**
     * @param document 文档
     * @param width    宽
     * @param height   高
     * @param stValue
     * @Description: 设置页面大小及纸张方向 landscape横向
     */
    public void setDocumentSize(XWPFDocument document, String width,
                                String height, STPageOrientation.Enum stValue) {
        CTSectPr sectPr = getDocumentCTSectPr(document);
        CTPageSz pgsz = sectPr.isSetPgSz() ? sectPr.getPgSz() : sectPr
                .addNewPgSz();
        pgsz.setH(new BigInteger(height));
        pgsz.setW(new BigInteger(width));
        pgsz.setOrient(stValue);
    }

    /**
     * @param document 文档
     * @param left     左
     * @param top      顶
     * @param right    右
     * @param bottom   底
     * @Description: 设置页边距 (word中1厘米约等于567)
     */
    public void setDocumentMargin(XWPFDocument document, String left,
                                  String top, String right, String bottom) {
        CTSectPr sectPr = getDocumentCTSectPr(document);
        CTPageMar ctpagemar = sectPr.addNewPgMar();
        if (StringUtils.isNotBlank(left)) {
            ctpagemar.setLeft(new BigInteger(left));
        }
        if (StringUtils.isNotBlank(top)) {
            ctpagemar.setTop(new BigInteger(top));
        }
        if (StringUtils.isNotBlank(right)) {
            ctpagemar.setRight(new BigInteger(right));
        }
        if (StringUtils.isNotBlank(bottom)) {
            ctpagemar.setBottom(new BigInteger(bottom));
        }
    }

    /**
     * @param document  文档
     * @param breakType
     * @Description: 添加新页
     */
    public void addNewPage(XWPFDocument document, BreakType breakType) {
        XWPFParagraph xp = document.createParagraph();
        xp.createRun().addBreak(breakType);
    }

    /**
     * 设置字体信息 设置字符间距信息(CTSignedTwipsMeasure)
     *
     * @param p             段落
     * @param isInsert      是否插入
     * @param isNewLine     是否新建一行
     * @param content       内容
     * @param fontFamily    字体
     * @param colorVal      颜色
     * @param fontSize      字体大小
     * @param isBlod        是否加粗
     * @param underPatterns 下划线
     * @param isItalic      是否斜体
     * @param isStrike      是否使用删除线
     * @param verticalAlign 垂直对齐
     * @param position      位置
     * @param spacingValue  间距
     */
    public void setTextFontInfo(XWPFParagraph p, boolean isInsert,
                                boolean isNewLine, String content, String fontFamily,
                                String colorVal, String fontSize, boolean isBlod,
                                UnderlinePatterns underPatterns, boolean isItalic,
                                boolean isStrike, VerticalAlign verticalAlign, int position,
                                String spacingValue) {
        XWPFRun pRun = null;
        if (isInsert) {
            pRun = p.createRun();
        } else {
            if (p.getRuns() != null && p.getRuns().size() > 0) {
                pRun = p.getRuns().get(0);
            } else {
                pRun = p.createRun();
            }
        }
        if (isNewLine) {
            pRun.addBreak();
        }
        pRun.setText(content);
        // 设置字体样式
        pRun.setBold(isBlod);
        pRun.setItalic(isItalic);
        pRun.setStrike(isStrike);
        if (underPatterns != null) {
            pRun.setUnderline(underPatterns);
        }
        pRun.setColor(colorVal);
        if (verticalAlign != null) {
            pRun.setSubscript(verticalAlign);
        }
        pRun.setTextPosition(position);

        CTRPr pRpr = null;
        if (pRun.getCTR() != null) {
            pRpr = pRun.getCTR().getRPr();
            if (pRpr == null) {
                pRpr = pRun.getCTR().addNewRPr();
            }
        } else {
            // pRpr = p.getCTP().addNewR().addNewRPr();
        }
        // 设置字体
        CTFonts fonts = pRpr.isSetRFonts() ? pRpr.getRFonts() : pRpr
                .addNewRFonts();
        fonts.setAscii(fontFamily);
        fonts.setEastAsia(fontFamily);
        fonts.setHAnsi(fontFamily);

        // 设置字体大小
        CTHpsMeasure sz = pRpr.isSetSz() ? pRpr.getSz() : pRpr.addNewSz();
        sz.setVal(new BigInteger(fontSize));

        CTHpsMeasure szCs = pRpr.isSetSzCs() ? pRpr.getSzCs() : pRpr
                .addNewSzCs();
        szCs.setVal(new BigInteger(fontSize));

        if (spacingValue != null) {
            // 设置字符间距信息
            CTSignedTwipsMeasure ctSTwipsMeasure = pRpr.isSetSpacing() ? pRpr
                    .getSpacing() : pRpr.addNewSpacing();
            ctSTwipsMeasure.setVal(new BigInteger(spacingValue));
        }
    }

    /**
     * @param url
     * @param text
     * @param paragraph
     * @param fontFamily
     * @param fontSize
     * @param isBlod
     * @param isItalic
     * @param isStrike
     * @param verticalAlign
     * @param position
     * @param spacingValue
     * @Description: 为段落添加超链接
     */
    public void appendExternalHyperlink(String url, String text,
                                        XWPFParagraph paragraph, String fontFamily, String fontSize,
                                        boolean isBlod, boolean isItalic, boolean isStrike,
                                        String verticalAlign, String position, String spacingValue) {
        // Add the link as External relationship
        String id = paragraph
                .getDocument()
                .getPackagePart()
                .addExternalRelationship(url,
                        XWPFRelation.HYPERLINK.getRelation()).getId();
        // Append the link and bind it to the relationship
        CTHyperlink cLink = paragraph.getCTP().addNewHyperlink();
        cLink.setId(id);

        // Create the linked text
        CTText ctText = CTText.Factory.newInstance();
        ctText.setStringValue(text);
        CTR ctr = CTR.Factory.newInstance();
        CTRPr rpr = ctr.addNewRPr();

        // 设置超链接样式
        CTColor color = CTColor.Factory.newInstance();
        color.setVal("0000FF");
        rpr.setColor(color);
        rpr.addNewU().setVal(STUnderline.SINGLE);
        if (isBlod) {
            rpr.addNewB().setVal(STOnOff.Enum.forString("true"));
        }
        if (isItalic) {
            rpr.addNewI().setVal(STOnOff.Enum.forString("true"));
        }
        if (isStrike) {
            rpr.addNewStrike().setVal(STOnOff.Enum.forString("true"));
        }
        if (verticalAlign != null) {
            rpr.addNewVertAlign().setVal(
                    STVerticalAlignRun.Enum.forString(verticalAlign));
        }
        rpr.addNewPosition().setVal(new BigInteger(position));

        // 设置字体
        CTFonts fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr
                .addNewRFonts();
        fonts.setAscii(fontFamily);
        fonts.setEastAsia(fontFamily);
        fonts.setHAnsi(fontFamily);

        // 设置字体大小
        CTHpsMeasure sz = rpr.isSetSz() ? rpr.getSz() : rpr.addNewSz();
        sz.setVal(new BigInteger(fontSize));

        CTHpsMeasure szCs = rpr.isSetSzCs() ? rpr.getSzCs() : rpr.addNewSzCs();
        szCs.setVal(new BigInteger(fontSize));

        if (spacingValue != null) {
            // 设置字符间距信息
            CTSignedTwipsMeasure ctSTwipsMeasure = rpr.isSetSpacing() ? rpr
                    .getSpacing() : rpr.addNewSpacing();
            ctSTwipsMeasure.setVal(new BigInteger(spacingValue));
        }

        ctr.setTArray(new CTText[]{ctText});
        cLink.setRArray(new CTR[]{ctr});
    }

    /**
     * 设置段落边框
     *
     * @param p
     * @param lborder
     * @param tBorders
     * @param rBorders
     * @param bBorders
     * @param btborders
     */
    public void setParagraphBorder(XWPFParagraph p, Borders lborder,
                                   Borders tBorders, Borders rBorders, Borders bBorders,
                                   Borders btborders) {
        if (lborder != null) {
            p.setBorderLeft(lborder);
        }
        if (tBorders != null) {
            p.setBorderTop(tBorders);
        }
        if (rBorders != null) {
            p.setBorderRight(rBorders);
        }
        if (bBorders != null) {
            p.setBorderBottom(bBorders);
        }
        if (btborders != null) {
            p.setBorderBetween(btborders);
        }
    }

    /**
     * @param table 目标表格
     * @param width 宽
     * @Description: 设置表格宽度
     */
    public void setTableWidth(XWPFTable table, String width) {
        CTTbl ttbl = table.getCTTbl();
        CTTblPr tblPr = ttbl.getTblPr() == null ? ttbl.addNewTblPr() : ttbl
                .getTblPr();
        CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr
                .addNewTblW();
        CTJc cTJc = tblPr.addNewJc();
        cTJc.setVal(STJc.Enum.forString("center"));
        tblWidth.setW(new BigInteger(width));
        tblWidth.setType(STTblWidth.DXA);
    }

    /**
     * @param doc       文档
     * @param paragraph 段落
     * @param pRun
     * @param title     标题
     * @param level     标题级别: "1"
     * @Description: 设置文档的标题
     */
    public void setDocTitle(XWPFDocument doc, XWPFParagraph paragraph,
                            XWPFRun pRun, String title, String level) {
        paragraph.setStyle(level);
        pRun = paragraph.createRun();
        pRun.setText(title);
        paragraph.setStyle(level);
        pRun = paragraph.createRun();
    }

    /**
     * @param document 文档
     * @param savePath 保存的路径
     * @throws Exception
     * @Description: 保存文档
     */
    public void saveDocument(XWPFDocument document, String savePath)
            throws Exception {
        FileOutputStream fos = new FileOutputStream(savePath);
        document.write(fos);
        fos.close();
    }

    /**
     * @param filePath 文件位置
     * @return
     * @throws Exception
     * @Description: 打开word文档
     */
    public XWPFDocument openDocument(String filePath) throws Exception {
        XWPFDocument xdoc = new XWPFDocument(
                POIXMLDocument.openPackage(filePath));
        return xdoc;
    }

    /**
     * 增加自定义标题样式。这里用的是stackoverflow的源码
     *
     * @param docxDocument 目标文档
     * @param strStyleId 样式名称
     * @param headingLevel 样式级别
     */
    public void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) {

        CTStyle ctStyle = CTStyle.Factory.newInstance();
        ctStyle.setStyleId(strStyleId);

        CTString styleName = CTString.Factory.newInstance();
        styleName.setVal(strStyleId);
        ctStyle.setName(styleName);

        CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
        indentNumber.setVal(BigInteger.valueOf(headingLevel));

        // lower number > style is more prominent in the formats bar
        ctStyle.setUiPriority(indentNumber);

        CTOnOff onoffnull = CTOnOff.Factory.newInstance();
        ctStyle.setUnhideWhenUsed(onoffnull);

        // style shows up in the formats bar
        ctStyle.setQFormat(onoffnull);

        // style defines a heading of the given level
        CTPPr ppr = CTPPr.Factory.newInstance();
        ppr.setOutlineLvl(indentNumber);
        ctStyle.setPPr(ppr);

        XWPFStyle style = new XWPFStyle(ctStyle);

        // is a null op if already defined
        XWPFStyles styles = docxDocument.createStyles();

        style.setType(STStyleType.PARAGRAPH);
        styles.addStyle(style);

    }

}

